#include <stdio.h>    
#include <stdlib.h>    
#include <string.h> 
#include <stdbool.h>   
#include <unistd.h>    
#include <sys/socket.h>    
#include <netinet/in.h>    
#include <pthread.h>    
#include <fcntl.h>    
#include <netdb.h>      //使用getnameinfo  将一个套接字地址结构转换成相应的主机和服务名字符串。
#include<arpa/inet.h>

#define PORT 8889
#define BUFFER_SIZE 1024    

pthread_mutex_t file_mutex;  

pthread_mutex_t file_mutex=PTHREAD_MUTEX_INITIALIZER;

typedef enum {    
    QUERY,    
    ADD,    
    UPDATE,    
    DELETE    
} OperationType;    
  
void send_response(int sockfd, const char* response) {    
    send(sockfd, response, strlen(response), 0);    
}    
  
void update_student_file(const char* filename, const char* id, const char* new_info) {  
    char temp_filename[256]; // 临时文件名  
    snprintf(temp_filename, sizeof(temp_filename), "%s.tmp", filename);  
  
    FILE *file = fopen(filename, "r");  
    FILE *temp_file = fopen(temp_filename, "w");  
    char buffer[BUFFER_SIZE];  
    char *id_in_line = NULL;  
  
    if (!file || !temp_file) {  
        // 错误处理：无法打开文件  
        return;  
    }  
  
    while (fgets(buffer, BUFFER_SIZE, file)) {  
        id_in_line = strstr(buffer, id); // 查找ID  
        if (id_in_line == buffer) { // 如果ID在行首，假设这是我们要更新的行  
            // 写入新信息（这里简单地替换整行，实际中可能需要更复杂的处理）  
            fprintf(temp_file, "%s\n", new_info);  
        } else {  
            // 否则，保留原行  
            fputs(buffer, temp_file);  
        }  
    }  
  
    fclose(file);  
    fclose(temp_file);  
  
    // 删除原文件，并将临时文件重命名为原文件名  
    remove(filename);  
    rename(temp_filename, filename);  
}  
void delete_student_file(const char* filename, const char* id) {  
    char temp_filename[256];  
    snprintf(temp_filename, sizeof(temp_filename), "%s.tmp", filename);  
  
    FILE *file = fopen(filename, "r");  
    FILE *temp_file = fopen(temp_filename, "w");  
    char buffer[BUFFER_SIZE];  
  
    if (!file || !temp_file) {  
        // 错误处理：无法打开文件  
        return;  
    }  
  
    while (fgets(buffer, BUFFER_SIZE, file)) {  
        if (strncmp(buffer, id, strlen(id)) != 0 ||(buffer[strlen(id)] != ','&&buffer[strlen(id)]!='\n'&&buffer[strlen(id)!='\0'])) {  
            // 如果行首不是ID或ID后不是逗号，则保留该行  
            fputs(buffer, temp_file);  
        }  
    }  
  
    fclose(file);  
    fclose(temp_file);  
  
    // 删除原文件，并将临时文件重命名为原文件名  
    remove(filename);  
    rename(temp_filename, filename);  
}

void* handle_client_thread(void* arg) {    
    int sockfd = *(int*)arg;    
    char buffer[BUFFER_SIZE] = {0};    
    struct sockaddr_in client_addr;  
    socklen_t client_len = sizeof(client_addr);  
    char client_ip[INET6_ADDRSTRLEN];
    uint16_t client_port;  
    
    // 获取客户端的IP和端口（在连接建立时获取一次即可）  
    getpeername(sockfd, (struct sockaddr *)&client_addr, &client_len);  
    client_port=ntohs(client_addr.sin_port);   
    getnameinfo((struct sockaddr *)&client_addr, client_len, client_ip, sizeof(client_ip),  
                NULL, 0, NI_NUMERICHOST);  
    while (1) {    
        int bytes_read = recv(sockfd, buffer, BUFFER_SIZE - 1,0);    
        if (bytes_read <= 0){
            //客户端断开连接
            printf("客户端 %s:%u 下线\n",client_ip,client_port);
            break;
        }    
        buffer[bytes_read] = '\0';
    
    OperationType operation;
    if (strncmp(buffer, "query+1", 7) == 0){
        operation = QUERY;
    }else if(strncmp(buffer, "add+", 4) == 0){
        operation = ADD;
    }else if(strncmp(buffer, "update+", 7) == 0){
        operation = UPDATE;
    }else if(strncmp(buffer, "delete+", 7) == 0){
        operation = DELETE;
    }else{
        operation = -1;
    }


    switch(operation){
        case QUERY :{
            char query_result[BUFFER_SIZE*10]={0};
            FILE *file=fopen("students.txt","r");
            if(file == NULL){
                send_response(sockfd,"文件打开失败,无法查询!\n");
                break;
            }
            char line[BUFFER_SIZE];
            while(fgets(line, BUFFER_SIZE, file)!= NULL){
                strcat(query_result,line);
            }
            fclose(file);
            if(strlen(query_result) > 0){
                send_response(sockfd,query_result);
            } else {
                send_response(sockfd,"没有学生信息可查询。\n");
            }
            break;
        }
        case ADD :{
            pthread_mutex_lock(&file_mutex);    
            FILE *file = fopen("students.txt", "a");   
            if(file){
                fseek(file,0,SEEK_SET);
                char line[BUFFER_SIZE];
                bool found = false;
                while(fgets(line,BUFFER_SIZE,file)){
                    if(strstr(line,buffer+4)!=NULL){
                        found = true;
                        break;
                    }
                }
                if(found){
                    send_response(sockfd,"添加失败，该学生信息已存在！");
                }else{
                    fputs(buffer+4,file);
                    send_response(sockfd, "添加成功!");
                }
            }
            else{
                send_response(sockfd,"添加失败！");
            }
            fclose(file);
            pthread_mutex_unlock(&file_mutex);
            break;
        }      
#if 0 
            if (file) {    
                fputs(buffer + 4, file);    
                //fputc('\n', file);        
                send_response(sockfd, "添加成功!");    
            } else {    
                send_response(sockfd, "添加失败!");    
            }    
            fclose(file);
            pthread_mutex_unlock(&file_mutex);
            break;
#endif
         
        case UPDATE :{
            char *id=strtok(buffer+7,",");
            char *new_info=strtok(NULL,"\n");
            if(id&&new_info){
                update_student_file("students.txt",id,new_info);
                send_response(sockfd,"更新成功!");
            }else{
                send_response(sockfd,"无效的更新命令或格式!\n");
            } 
            break;   
        }
        case DELETE :{
            char *id = strtok(buffer + 7, "\n");  
            if (id) {  
                delete_student_file("students.txt", id);  
                send_response(sockfd, "成功删除!\n");  
            } else {  
                send_response(sockfd, "无效的删除命令或格式!\n");  
            } 
            break; 
        }
        default :{
            send_response(sockfd, "无此命令!\n");  
            break;
        }
        
    }
     
    }
    close(sockfd);    
    free((int*)arg);  // 正确释放内存  
    return NULL;   
}

int main(){  
    int server_fd, new_socket;  
    struct sockaddr_in address;  
    int addrlen = sizeof(address);  
  
    // 创建socket  
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {  
        perror("socket");  
        exit(-1);  
    }  
  
    // 绑定地址和端口  
    address.sin_family = AF_INET;  
    address.sin_addr.s_addr = inet_addr("192.168.10.188");  
    address.sin_port = htons(PORT);  
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {  
        perror("bind");  
        exit(-1);  
    }  
  
    // 监听  
    if (listen(server_fd, 3) < 0) {  
        perror("listen");  
        exit(-1);  
    }  
    printf("正在监听端口%d...\n",PORT);
  
    // 处理客户端连接  
    while (1){  
        socklen_t sin_size = sizeof(struct sockaddr_in);  
        new_socket = accept(server_fd, (struct sockaddr *)&address, &sin_size);  
        if (new_socket < 0) {  
            perror("accept");  
            exit(-1);  
        }  
  
        // 获取并打印客户端的IP地址和端口号  
        char client_ip[INET6_ADDRSTRLEN];  
        uint16_t client_port;  
        struct sockaddr_in *client_addr = (struct sockaddr_in *)&address;  
        getnameinfo((struct sockaddr *)client_addr, sin_size, client_ip, sizeof(client_ip),  
                    NULL, 0, NI_NUMERICHOST);  //NI_NUMERICHOST将IP地址转换成数字形式，如“192.168.1.1”
        client_port = ntohs(client_addr->sin_port);  
        printf("客户端 %s:%u 已上线\n", client_ip, client_port);  
        
        //注意下面三行代码
        pthread_t thread_id;  
        int *sock_desc = malloc(sizeof(int));  
        *sock_desc = new_socket;  //该指针用于在新线程中传递客户端的套接字描述符
  
        if (pthread_create(&thread_id, NULL, handle_client_thread, (void *)sock_desc) < 0) {  
            perror("could not create thread");  
            close(new_socket);  
            free(sock_desc);  
            continue;  
        }  
  
        pthread_detach(thread_id);  //线程分离状态，线程结束后，资源自动回收
    }  
    return 0;
}